<div class="content-section introduction">
    <div class="feature-intro">
        <h1>Tree</h1>
        <p>Tree is used to display hierarchical data.</p>
    </div>
</div>

<div class="content-section implementation">
    <div class="card">
        <h5>Basic</h5>
        <p-tree [value]="files1"></p-tree>

        <h5>Programmatic</h5>
        <div style="margin-bottom: 1rem">
            <button pButton type="button" label="Expand all" (click)="expandAll()" style="margin-right: .5rem"></button>
            <button pButton type="button" label="Collapse all" (click)="collapseAll()"></button>
        </div>
        <p-tree [value]="files2"></p-tree>
    </div>
</div>

<div class="content-section documentation">
    <p-tabView>
        <p-tabPanel header="Documentation">
            <h5>CDK</h5>
            <p>VirtualScrolling depends on @angular/cdk's ScrollingModule so begin with installing CDK if not already installed.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
npm install @angular/cdk --save
</app-code>

            <h5>Import</h5>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;TreeModule&#125; from 'primeng/tree';
import &#123;TreeNode&#125; from 'primeng/api';
</app-code>

            <h5>Getting Started</h5>
            <p>Tree component requires an array of TreeNode objects as its value. Let's begin with the TreeNode api. Note that all of the properties are optional.</p>

            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Type</th>
                            <th>Default</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>label</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Label of the node.</td>
                        </tr>
                        <tr>
                            <td>data</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Data represented by the node.</td>
                        </tr>
                        <tr>
                            <td>icon</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Icon of the node to display next to content.</td>
                        </tr>
                        <tr>
                            <td>expandedIcon</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Icon to use in expanded state.</td>
                        </tr>
                        <tr>
                            <td>collapsedIcon</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Icon to use in collapsed state.</td>
                        </tr>
                        <tr>
                            <td>children</td>
                            <td>TreeNode[]</td>
                            <td>null</td>
                            <td>An array of treenodes as children.</td>
                        </tr>
                        <tr>
                            <td>leaf</td>
                            <td>boolean</td>
                            <td>null</td>
                            <td>Specifies if the node has children. Used in lazy loading.</td>
                        </tr>
                        <tr>
                            <td>style</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the node.</td>
                        </tr>
                        <tr>
                            <td>styleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the node.</td>
                        </tr>
                        <tr>
                            <td>expanded</td>
                            <td>boolean</td>
                            <td>null</td>
                            <td>Whether the node is in an expanded or collapsed state.</td>
						</tr>
                        <tr>
                            <td>type</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Type of the node to match ng-template type.</td>
                        </tr>
                        <tr>
                            <td>parent</td>
                            <td>TreeNode</td>
                            <td>null</td>
                            <td>Parent of the node.</td>
                        </tr>
                        <tr>
                            <td>draggable</td>
                            <td>boolean</td>
                            <td>null</td>
                            <td>Whether to disable dragging for a particular node even if draggableNodes is enabled.</td>
                        </tr>
                        <tr>
                            <td>droppable</td>
                            <td>boolean</td>
                            <td>null</td>
                            <td>Whether to disable dropping for a particular node even if droppableNodes is enabled.</td>
                        </tr>
                        <tr>
                            <td>selectable</td>
                            <td>boolean</td>
                            <td>null</td>
                            <td>Used to disable selection of a particular node.</td>
                        </tr>
                        <tr>
                            <td>key</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Unique key of the node.(<a href="https://github.com/primefaces/primeng/issues/7237#issue-409791407" target="_blank" rel="noopener noreferrer">more</a>)</td>
                        </tr>
                        <tr>
                            <td>emptyMessage</td>
                            <td>string</td>
                            <td>No records found.</td>
                            <td>Text to display when there is no data.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <p>Most of the time, nodes will be loaded from a remote datasoure, here is an example NodeService that fetches the data from a json file.</p>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
@Injectable()
export class NodeService &#123;

    constructor(private http: Http) &#123;&#125;

    getFiles() &#123;
        return this.http.get('showcase/resources/data/files.json')
                    .toPromise()
                    .then(res =&gt; &lt;TreeNode[]&gt; res.json().data);
    &#125;
&#125;
</app-code>

        <p>The files.json file consists of sample data. In a real application, this should be a dynamic response generated from the remote call.</p>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
&#123;
    "data":
    [
        &#123;
            "label": "Documents",
            "data": "Documents Folder",
            "expandedIcon": "pi pi-folder-open",
            "collapsedIcon": "pi pi-folder",
            "children": [&#123;
                    "label": "Work",
                    "data": "Work Folder",
                    "expandedIcon": "pi pi-folder-open",
                    "collapsedIcon": "pi pi-folder",
                    "children": [&#123;"label": "Expenses.doc", "icon": "pi pi-file", "data": "Expenses Document"&#125;, &#123;"label": "Resume.doc", "icon": "pi pi-file", "data": "Resume Document"&#125;]
                &#125;,
                &#123;
                    "label": "Home",
                    "data": "Home Folder",
                    "expandedIcon": "pi pi-folder-open",
                    "collapsedIcon": "pi pi-folder",
                    "children": [&#123;"label": "Invoices.txt", "icon": "pi pi-file", "data": "Invoices for this month"&#125;]
                &#125;]
        &#125;,
        &#123;
            "label": "Pictures",
            "data": "Pictures Folder",
            "expandedIcon": "pi pi-folder-open",
            "collapsedIcon": "pi pi-folder",
            "children": [
                &#123;"label": "barcelona.jpg", "icon": "pi pi-image", "data": "Barcelona Photo"&#125;,
                &#123;"label": "logo.jpg", "icon": "pi pi-file", "data": "PrimeFaces Logo"&#125;,
                &#123;"label": "primeui.png", "icon": "pi pi-image", "data": "PrimeUI Logo"&#125;]
        &#125;,
        &#123;
            "label": "Movies",
            "data": "Movies Folder",
            "expandedIcon": "pi pi-folder-open",
            "collapsedIcon": "pi pi-folder",
            "children": [&#123;
                    "label": "Al Pacino",
                    "data": "Pacino Movies",
                    "children": [&#123;"label": "Scarface", "icon": "pi pi-video", "data": "Scarface Movie"&#125;, &#123;"label": "Serpico", "icon": "pi pi-file-video", "data": "Serpico Movie"&#125;]
                &#125;,
                &#123;
                    "label": "Robert De Niro",
                    "data": "De Niro Movies",
                    "children": [&#123;"label": "Goodfellas", "icon": "pi pi-video", "data": "Goodfellas Movie"&#125;, &#123;"label": "Untouchables", "icon": "pi pi-video", "data": "Untouchables Movie"&#125;]
                &#125;]
        &#125;
    ]
&#125;
</app-code>

        <p>The component that uses this service makes a call to getFiles() and assigns them back to files property that is bound to the tree.</p>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class TreeDemoComponent implements OnInit &#123;

    files: TreeNode[];

    constructor(private nodeService: NodeService) &#123;&#125;

    ngOnInit() &#123;
        this.nodeService.getFiles().then(files => this.files = files);
    &#125;

&#125;
</app-code>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files"&gt;&lt;/p-tree&gt;
</app-code>

            <h5>Selection</h5>
            <p>Tree supports 3 selection methods, single, multiple and checkbox. Selection is enabled by setting <i>selectionMode</i> property and providing a single TreeNode or
            an array of TreeNodes to reference the selections depending on the selection mode.</p>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class TreeDemoComponent implements OnInit &#123;

    files: TreeNode[];

    selectedFile: TreeNode;

    constructor(private nodeService: NodeService) &#123;&#125;

    ngOnInit() &#123;
        this.nodeService.getFiles().then(files => this.files = files);
    &#125;

&#125;
</app-code>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" selectionMode="single" [(selection)]="selectedFile"&gt;&lt;/p-tree&gt;
</app-code>

        <p>In multiple mode or checkbox mode, selection property should be an array. In multiple mode, items can either be selected
        using metaKey or toggled individually depending on the value of metaKeySelection property value which is true by default. On touch enabled
        devices metaKeySelection is turned off automatically. In checkbox mode, when inititing a tree with preselections, also set partialSelected
        property on node so that minus icon can be displayed when necessary.</p>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
    export class TreeDemoComponent implements OnInit &#123;

        files: TreeNode[];

        selectedFiles: TreeNode[];

        constructor(private nodeService: NodeService) &#123;&#125;

        ngOnInit() &#123;
            this.nodeService.getFiles().then(files => this.files = files);
        &#125;

    &#125;
</app-code>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" selectionMode="single" [(selection)]="selectedFiles"&gt;&lt;/p-tree&gt;
</app-code>

            <p>In checkbox mode, selections propagate up and down, if you prefer not to do so, propagation can be turned off by <i>propagateSelectionDown</i> and
            <i>propagateSelectionUp</i> properties.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" selectionMode="checkbox" [(selection)]="selectedFiles"
                [propagateSelectionUp]="false" [propagateSelectionDown]="false"&gt;&lt;/p-tree&gt;
</app-code>

            <p>Tree provides <i>onNodeSelect</i> and <i>onNodeUnselect</i> options as callbacks for selection feature.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" selectionMode="single" [(selection)]="selectedFiles" (onNodeSelect)="nodeSelect($event)" (onNodeUnselect)="nodeUnselect($event)"&gt;&lt;/p-tree&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class TreeDemoComponent implements OnInit &#123;

    files: TreeNode[];

    selectedFiles: TreeNode[];

    constructor(private nodeService: NodeService) &#123;&#125;

    ngOnInit() &#123;
        this.nodeService.getFiles().then(files => this.files = files);
    &#125;

    nodeSelect(event) &#123;
        //event.node = selected node
    &#125;

&#125;
</app-code>

            <p>Selection of a particular node can be disabled by setting the <i>selectable</i> property of the node to false.</p>

            <h5>Icons</h5>
            <p>Icon of a treenode is defined using the icon property, if you need an icon depending on the expand or collapse state, use
                <i>expandedIcon</i> and <i>collapsedIcon</i> instead.</p>

            <h5>Templating</h5>
            <p>By default label of a treenode is displayed inside a tree node, in case you need to place custom content define a pTemplate that gets
                the treenode as an implicit variable. Example below places an input field to create editable treenodes.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files"&gt;
    &lt;ng-template let-node  pTemplate="default"&gt;
        &lt;input [(ngModel)]="node.label" type="text" style="width:100%"&gt;
    &lt;/ng-template&gt;
&lt;/p-tree&gt;
</app-code>

            <p>Multiple templates are supported by matching the type property of the TreeNode with the type of pTemplate. If a node has no type,
            then default <i>ng-template</i> is used.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files"&gt;
    &lt;ng-template let-node  pTemplate="picture"&gt;
        &lt;img [attrs.src]="picture.path"&gt;
    &lt;/ng-template&gt;
    &lt;ng-template let-node  pTemplate="default"&gt;
        &lt;input [(ngModel)]="node.label" type="text" style="width:100%"&gt;
    &lt;/ng-template&gt;
&lt;/p-tree&gt;
</app-code>

            <h5>Filtering</h5>
            <p>Filtering is enabled by setting the <i>filter</i> property to true, by default label property of a node
                is used to compare against the value in the text field, in order to customize which field(s) should be used during search define <i>filterBy</i> property.</p>

            <p>In addition <i>filterMode</i> specifies the filtering strategy. In <b>lenient</b> mode when the query matches a node, children of the node are not searched further as all descendants of the node are included. On the other hand,
                    in <b>strict</b> mode when the query matches a node, filtering continues on all descendants.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="filesTree11" [filter]="true">&lt;/p-tree&gt;

&lt;p-tree [value]="filesTree12" [filter]="true" filterMode="strict"&gt;&lt;/p-tree&gt;
</app-code>

            <h5>ContextMenu</h5>
            <p>Tree has exclusive integration with context menu created by binding a menu instance to the tree.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" selectionMode="single" [(selection)]="selectedFile2" [contextMenu]="cm"&gt;&lt;/p-tree&gt;

&lt;p-contextMenu #cm [model]="items"&gt;&lt;/p-contextMenu&gt;
</app-code>

            <h5>Lazy Loading</h5>
            <p>Lazy loading is handy to deal with large datasets. Instead of loading the whole tree, nodes can be loaded at <i>onNodeExpand</i> event.
            Important part of implementing lazy loading is defining leaf property of a node as false, this will instruct tree to display an arrow icon
            to indicate there are children of this node although they are not loaded yet. When the lazy node is expanded, onNodeExpand is called
            and a remote call can be made to add the children to the expanded node.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" (onNodeExpand)="loadNode($event)"&gt;&lt;/p-tree&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class TreeDemoComponent implements OnInit &#123;

    files: TreeNode[];

    selectedFiles: TreeNode[];

    constructor(private nodeService: NodeService) &#123;&#125;

    ngOnInit() &#123;
        //initial nodes
        this.nodeService.getFiles().then(files => this.files = files);
    &#125;

    loadNode(event) &#123;
        if (event.node) &#123;
            //in a real application, make a call to a remote url to load children of the current node and add the new nodes as children
            this.nodeService.getLazyFiles().then(nodes => event.node.children = nodes);
        &#125;
    &#125;

&#125;
</app-code>

            <p>Assume at ngOnInit tree is initialized with a data like below that has nodes having no actual children but leaf property is set false.</p>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
&#123;
    "data":
    [
        &#123;
            "label": "Lazy Node 0",
            "data": "Node 0",
            "expandedIcon": "pi pi-folder",
            "collapsedIcon": "pi pi-folder",
            "leaf": false
        &#125;,
        &#123;
            "label": "Lazy Node 1",
            "data": "Node 1",
            "expandedIcon": "pi pi-folder-open",
            "collapsedIcon": "pi pi-folder",
            "leaf": false
        &#125;,
        &#123;
            "label": "Lazy Node 1",
            "data": "Node 2",
            "expandedIcon": "pi pi-folder-open",
            "collapsedIcon": "pi pi-folder",
            "leaf": false
        &#125;
    ]
&#125;
</app-code>

                <h5>Scrolling</h5>
                <p>Scrolling is used to preserve space as content of the tree is dynamic and enabled by <i>scrollHeight</i> property.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" scrollHeight="200px"&gt;&lt;/p-tree&gt;
</app-code>

                <h5>Flex Scroll</h5>
                <p>In cases where viewport should adjust itself according to the table parent's height instead of a fixed viewport height, set <i>scrollHeight</i> option as <b>flex</b>. In example below,
                table is inside a Dialog where viewport size dynamically responds to the dialog size changes such as resizing or maximizing.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;button type="button" (click)="showDialog()" pButton icon="pi pi-external-link" label="View"&gt;&lt;/button&gt;
&lt;p-dialog header="Flexible ScrollHeight" [(visible)]="dialogVisible" [style]="&#123;width: '50vw'&#125;" [baseZIndex]="10000" [maximizable]="true" [modal]="true" 
    [resizable]="true" [contentStyle]="&#123;height: '300px'&#125;" styleClass="p-fluid"&gt;
    &lt;p-tree [value]="files2" scrollHeight="flex"&gt;&lt;/p-tree&gt;   
&lt;/p-dialog&gt;
</app-code>

                <h5>Virtual Scrolling</h5>
                <p>VirtualScroller is a performant approach to handle huge data efficiently. Setting <i>virtualScroll</i> property as true and providing a <i>virtualNodeHeight</i> in pixels would be enough to enable this functionality.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" [virtualScroll]="true" [virtualNodeHeight]="33" scrollHeight="200px"&gt;&lt;/p-tree&gt;
</app-code>

            <h5>Drag and Drop</h5>
            <p>Nodes can be reordered within a tree and also can be transferred between multiple trees. To enable dragging from a tree set <i>draggableNodes</i> to true and to allow
            dropping enable <i>droppableNodes</i> property. In addition, import TreeDragDropService and configure it as a provider at your component or module.</p>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;TreeDragDropService&#125; from 'primeng/api';
</app-code>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" draggableNodes="true" droppableNodes="true"&gt;&lt;/p-tree&gt;
</app-code>
            <p>Multiple trees can be used in a drag drop operation, in order to add constraints like rejecting drags from a certain tree but allow from another use draggableScope
            and droppableScope properties which can be a string or an array. Following example uses 3 trees where second one only accepts drags from first tree and second one only
            accepts from second tree whereas first tree accepts drops from 3rd tree.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="a" droppableScope="c"&gt;&lt;/p-tree&gt;
&lt;p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="b" droppableScope="a"&gt;&lt;/p-tree&gt;
&lt;p-tree [value]="files" draggableNodes="true" droppableNodes="true" draggableScope="c" droppableScope="b"&gt;&lt;/p-tree&gt;
</app-code>

            <p>In case, a drop should be accepted based on a condition, enable validateDrop property, define an event handler for <i>onNodeDrop</i> where the passed event and call the accept callback of the event
                to accept a drop. Simply emitting the call of <i>accept()</i> will reject the drop.
            </p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" draggableNodes="true" droppableNodes="true" [validateDrop]="true" (onNodeDrop)="onDrop($event)"&gt;&lt;/p-tree&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
onDrop(event) &#123;
    if (condition) &#123;
        event.accept();
    &#125;
&#125;
</app-code>

            <h5>Loading Status</h5>
            <p>Tree has a loading property, when enabled a spinner icon is displayed to indicate data load.</p>
            <p>An optional loadingIcon property can be passed in case you prefer a different icon.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" [loading]="loading"&gt;&lt;/p-tree&gt;
</app-code>

            <h5>Horizontal Orientation</h5>
            <p>Horizontal mode is the alternative option for orientation.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-tree [value]="files" layout="horizontal"&gt;&lt;/p-tree&gt;
</app-code>

            <h5>Properties</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Type</th>
                            <th>Default</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                         <tr>
                            <td>value</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of treenodes.</td>
                        </tr>
                        <tr>
                            <td>selectionMode</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Defines the selection mode, valid values "single", "multiple", and "checkbox".</td>
                        </tr>
                        <tr>
                            <td>selection</td>
                            <td>any</td>
                            <td>null</td>
                            <td>A single treenode instance or an array to refer to the selections.</td>
                        </tr>
                        <tr>
                            <td>style</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Inline style of the component.</td>
                        </tr>
                        <tr>
                            <td>styleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the component.</td>
                        </tr>
                        <tr>
                            <td>contextMenu</td>
                            <td>ContextMenu</td>
                            <td>null</td>
                            <td>Context menu instance.</td>
                        </tr>
                        <tr>
                            <td>layout</td>
                            <td>string</td>
                            <td>vertical</td>
                            <td>Defines the orientation of the tree, valid values are 'vertical' and 'horizontal'.</td>
                        </tr>
                        <tr>
                            <td>draggableScope</td>
                            <td>string/array</td>
                            <td>null</td>
                            <td>Scope of the draggable nodes to match a droppableScope.</td>
                        </tr>
                        <tr>
                            <td>droppableScope</td>
                            <td>string/array</td>
                            <td>null</td>
                            <td>Scope of the droppable nodes to match a draggableScope.</td>
                        </tr>
                        <tr>
                            <td>draggableNodes</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the nodes are draggable.</td>
                        </tr>
                        <tr>
                            <td>droppableNodes</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the nodes are droppable.</td>
                        </tr>
                        <tr>
                            <td>metaKeySelection</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item
                            can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically.</td>
                        </tr>
                        <tr>
                            <td>propagateSelectionUp</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether checkbox selections propagate to ancestor nodes.</td>
                        </tr>
                        <tr>
                            <td>propagateSelectionDown</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether checkbox selections propagate to descendant nodes.</td>
                        </tr>
                        <tr>
                            <td>loading</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Displays a loader to indicate data load is in progress.</td>
                        </tr>
                        <tr>
                            <td>loadingIcon</td>
                            <td>string</td>
                            <td>pi pi-spinner</td>
                            <td>The icon to show while indicating data load is in progress.</td>
                        </tr>
                        <tr>
                            <td>emptyMessage</td>
                            <td>string</td>
                            <td>No records found</td>
                            <td>Text to display when there is no data.</td>
                        </tr>
                        <tr>
                            <td>ariaLabel</td>
                            <td>string</td>
                            <td></td>
                            <td>Used to define a string that labels the tree.</td>
                        </tr>
                        <tr>
                            <td>ariaLabelledBy</td>
                            <td>string</td>
                            <td>pi pi-spinner</td>
                            <td>Establishes relationships between the component and label(s) where its value should be one or more element IDs.</td>
                        </tr>
                        <tr>
                            <td>validateDrop</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, drop can be accepted or rejected based on condition defined at onNodeDrop.</td>
                        </tr>
                        <tr>
                            <td>filter</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When specified, displays an input field to filter the items.</td>
                        </tr>
                        <tr>
                            <td>filterBy</td>
                            <td>string</td>
                            <td>label</td>
                            <td>When filtering is enabled, filterBy decides which field or fields (comma separated) to search against.</td>
                        </tr>
                        <tr>
                            <td>filterMode</td>
                            <td>string</td>
                            <td>lenient</td>
                            <td>Mode for filtering valid values are "lenient" and "strict". Default is lenient.</td>
                        </tr>
                        <tr>
                            <td>filterPlaceholder</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Placeholder text to show when filter input is empty.</td>
                        </tr>
                        <tr>
                            <td>filterLocale</td>
                            <td>string</td>
                            <td>undefined</td>
                            <td>Locale to use in filtering. The default locale is the host environment's current locale.</td>
                        </tr>
                        <tr>
                            <td>scrollHeight</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Height of the scrollable viewport.</td>
                        </tr>
                        <tr>
                            <td>virtualScroll</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the data should be rendered on demand during scroll.</td>
                        </tr>
                        <tr>
                            <td>virtualNodeHeight</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Height of a node to use in calculations of virtual scrolling.</td>
                        </tr>
                        <tr>
                            <td>minBufferPx</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Minimum amount of content buffer (in pixels) that the viewport must render.</td>
                        </tr>
                        <tr>
                            <td>maxBufferPx</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Configures how much buffer space to render back up to when it detects that more buffer is required.</td>
                        </tr>
                        <tr>
                            <td>trackBy</td>
                            <td>Function</td>
                            <td>null</td>
                            <td>Function to optimize the node list rendering, default algoritm checks for object identity.</td>
                        </tr>
                        <tr>
                            <td>indentation</td>
                            <td>number</td>
                            <td>1.5</td>
                            <td>Indentation factor for spacing of the nested node when virtual scrolling is enabled.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Events</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                            <th>Description</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>onNodeSelect</td>
                            <td>event.originalEvent: browser event <br>
                                event.node: Selected node instance.</td>
                            <td>Callback to invoke when a node is selected.</td>
                        </tr>
                        <tr>
                            <td>onNodeUnselect</td>
                            <td>event.originalEvent: browser event <br>
                                event.node: Unselected node instance.</td>
                            <td>Callback to invoke when a node is unselected.</td>
                        </tr>
                        <tr>
                            <td>onNodeExpand</td>
                            <td>event.originalEvent: browser event <br>
                                event.node: Expanded node instance.</td>
                            <td>Callback to invoke when a node is expanded.</td>
                        </tr>
                        <tr>
                            <td>onNodeCollapse</td>
                            <td>event.originalEvent: browser event <br>
                                event.node: Collapsed node instance.</td>
                            <td>Callback to invoke when a node is collapsed.</td>
                        </tr>
                        <tr>
                            <td>onNodeContextMenuSelect</td>
                            <td>event.originalEvent: browser event <br>
                                event.node: Selected node instance.</td>
                            <td>Callback to invoke when a node is selected with right click.</td>
                        </tr>
                        <tr>
                            <td>onNodeDrop</td>
                            <td>event.originalEvent: browser event <br>
                                event.dragNode: Dragged node instance <br>
                                event.dropNode: Dropped node instance.
                                event.index: Index of the dropped node within siblings.</td>
                            <td>Callback to invoke when a node is dropped.</td>
                        </tr>
                        <tr>
                            <td>onFilter</td>
                            <td>event.filter: Filter value used in filtering.<br>
                                event.filteredValue: Filtered data after running the filtering.</td>
                            <td>Callback to invoke when data is filtered.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Styling</h5>
            <p>Following is the list of structural style classes, for theming classes visit <a href="#" [routerLink]="['/theming']">theming page</a>.</p>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Element</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>p-tree</td>
                            <td>Main container element</td>
                        </tr>
                        <tr>
                            <td>p-tree-horizontal</td>
                            <td>Main container element in horizontal mode</td>
                        </tr>
                        <tr>
                            <td>p-tree-container</td>
                            <td>Container of nodes</td>
                        </tr>
                        <tr>
                            <td>p-treenode</td>
                            <td>A treenode element</td>
                        </tr>
                        <tr>
                            <td>p-treenode-content</td>
                            <td>Content of a treenode</td>
                        </tr>
                        <tr>
                            <td>p-treenode-toggler</td>
                            <td>Toggle icon</td>
                        </tr>
                        <tr>
                            <td>p-treenode-icon</td>
                            <td>Icon of a treenode</td>
                        </tr>
                        <tr>
                            <td>p-treenode-label</td>
                            <td>Label of a treenode</td>
                        </tr>
                        <tr>
                            <td>p-treenode-children</td>
                            <td>Container element for node children</td>
                        </tr>
                        <tr>
                            <td>p-treenode-content-selected</td>
                            <td>Content of a selected node.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Dependencies</h5>
            <p>None.</p>
        </p-tabPanel>

        <p-tabPanel header="Source">
            <a href="https://github.com/primefaces/primeng/tree/master/src/app/showcase/components/tree" class="btn-viewsource" target="_blank">
                <span>View on GitHub</span>
            </a>
            <a href="https://stackblitz.com/edit/primeng-tree-demo" class="btn-viewsource" style="margin-left: .5em;" target="_blank">
                <span>Edit in StackBlitz</span>
            </a>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;h5&gt;Basic&lt;/h5&gt;
&lt;p-tree [value]="files1"&gt;&lt;/p-tree&gt;

&lt;h5&gt;Programmatic&lt;/h5&gt;
&lt;div style="margin-bottom: 1rem"&gt;
    &lt;button pButton type="button" label="Expand all" (click)="expandAll()" style="margin-right: .5rem"&gt;&lt;/button&gt;
    &lt;button pButton type="button" label="Collapse all" (click)="collapseAll()"&gt;&lt;/button&gt;
&lt;/div&gt;
&lt;p-tree [value]="files2"&gt;&lt;/p-tree&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;Component,OnInit&#125; from '@angular/core';
import &#123;NodeService&#125; from '../../service/nodeservice';
import &#123;TreeNode&#125; from 'primeng/api';

@Component(&#123;
    templateUrl: './treebasicdemo.html'
&#125;)
export class TreeBasicDemo implements OnInit &#123;

    files1: TreeNode[];
    
    files2: TreeNode[];
    
    constructor(private nodeService: NodeService) &#123; &#125;

    ngOnInit() &#123;
        this.nodeService.getFiles().then(files => this.files1 = files);
        this.nodeService.getFiles().then(files => this.files2 = files);
    &#125;
    
    expandAll()&#123;
        this.files2.forEach( node => &#123;
            this.expandRecursive(node, true);
        &#125; );
    &#125;

    collapseAll()&#123;
        this.files2.forEach( node => &#123;
            this.expandRecursive(node, false);
        &#125; );
    &#125;
    
    private expandRecursive(node:TreeNode, isExpand:boolean)&#123;
        node.expanded = isExpand;
        if (node.children)&#123;
            node.children.forEach( childNode => &#123;
                this.expandRecursive(childNode, isExpand);
            &#125; );
        &#125;
    &#125;
&#125;
</app-code>
        </p-tabPanel>
        <p-tabPanel header="StackBlitz">
            <ng-template pTemplate="content">
                <iframe src="https://stackblitz.com/edit/primeng-tree-demo?embed=1" style="width: 100%; height: 768px; border: none;"></iframe>
            </ng-template>
        </p-tabPanel>
    </p-tabView>
</div>
